package com.gz.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.IdUtil;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.domain.AlipayTradePagePayModel;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gz.common.RedisConst;

import com.gz.config.AlipayConfigOriginal;
import com.gz.entity.*;
import com.gz.entity.Vo.CartItemVo;
import com.gz.entity.Vo.CartVo;
import com.gz.entity.Vo.OrderItemVo;
import com.gz.entity.Vo.OrderVo;
import com.gz.exception.Assert;
import com.gz.exception.BusinessCode;
import com.gz.mapper.AddressMapper;
import com.gz.mapper.ItemMapper;
import com.gz.service.BookService;
import com.gz.service.CartService;
import com.gz.service.ItemService;
import com.gz.service.OrderService;
import com.gz.mapper.OrderMapper;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
* @author 龙龙与贝儿
* @description 针对表【t_order】的数据库操作Service实现
* @createDate 2025-05-22 16:34:29
*/
@Slf4j
@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order>
    implements OrderService{
    @Autowired
    private AlipayClient alipayClient;   //支付宝提供的客户端

    @Autowired
    private AlipayConfigOriginal alipayConfigOriginal;   //使用自定义配置类与Alipay中一个类同名

    @Autowired
    private OrderMapper orderMapper;  //订单数据层

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private CartService cartService;   //购物车业务层

    @Autowired
    private ItemMapper itemMapper;   //订单项

    @Autowired
    ItemService itemService;

    @Autowired
    private RabbitTemplate rabbitTemplate;   //消息队列

    @Autowired
    private AddressMapper addressMapper;

    @Autowired
    private BookService bookService;
    @Autowired
    RedissonClient redissonClient;

    @Override
    @Transactional  //开启事务，因为有多个插入操作
    public String addNewOrder(Long userId, Integer addressId) {
        long orderId1 = IdUtil.getSnowflake(1, 1).nextId();
        String orderId= String.valueOf(orderId1);
        CartVo cart =(CartVo) redisTemplate.opsForValue().get(RedisConst.USER_CART_PREFIX + ":" + userId);
        HashOperations ops = redisTemplate.opsForHash();

        for(CartItemVo cartItem:cart.getItemList()){
            //使用Redisson实现分布式锁，解决超卖问题
            RLock lock = redissonClient.getLock(RedisConst.LOCK_PREFIX + ":" + cartItem.getBookId());
            try {
                //加锁
                lock.lock(10, TimeUnit.SECONDS);

                //获取这本书籍的库存
                Integer storeCount = (Integer) ops.get(RedisConst.BOOK_STORAGE, cartItem.getBookId().toString());
                //库存量小于购买量，应该返回：库存不足
                Assert.error(storeCount < cartItem.getQuantity(), BusinessCode.STORAGE_NOT_ENOUGH);
                //库存量是充足的，扣减Redis的库存 (加上负数)
                ops.increment(RedisConst.BOOK_STORAGE, cartItem.getBookId().toString(), -cartItem.getQuantity());

                log.info("书籍id:{}, 书籍库存:{}", cartItem.getBookId(), storeCount);
            } finally {
                //持有锁才释放锁
                if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                    lock.unlock();
                    log.info("释放锁: {}", lock);
                }
            }
//            Integer storeCount=(Integer) hashOperations.get(RedisConst.BOOK_STORAGE,cartItem.getBookId().toString());
//            Assert.error(storeCount<cartItem.getQuantity(), BusinessCode.STORAGE_NOT_ENOUGH);
//            hashOperations.increment(RedisConst.BOOK_STORAGE,cartItem.getBookId().toString(),-cartItem.getQuantity());
//            log.info("书籍id:{}, 书籍库存:{}", cartItem.getBookId(), storeCount);

            Item item = new Item();
            item.setBookId(cartItem.getBookId());
            item.setBookName(cartItem.getName());
            item.setPrice(cartItem.getPrice());
            item.setBuyCount(cartItem.getQuantity());
            item.setSumPrice(cartItem.getPriceToQuantitySum());
            item.setOrderId(orderId);
            item.setState(OrderStatus.NO_PAY.getCode());
            itemMapper.insert(item);
        }
        //5、创建订单对象
        Order order = new Order();
        order.setId(orderId);  //主键
        String orderNum = "MI_BOOK_" + orderId;
        order.setOrderNum(orderNum);   //订单号自定义：前缀+雪花
        order.setTotalPrice(cart.getTotalPrice());   //总价格
        order.setUserId(userId); //用户id
        order.setAddressId(addressId);  //地址id
        order.setState(OrderStatus.NO_PAY.getCode());  //待付款
        //写到数据库中
        orderMapper.insert(order);
        log.info("订单创建成功，订单号：{}", orderNum);

        //6、清空Redis中的购物车，使用异步操作
        rabbitTemplate.convertAndSend("clear.cart.queue", cart);

        //7、将订单存入死信队列（40分钟）中，定时判断用户是否已经完成订单支付
        rabbitTemplate.convertAndSend("order.exchange", "order.key.normal", order);

        //返回订单号
        return orderNum;

    }

    @Override
    public List<OrderVo> queryOrder(Long userId, Integer status) {
        //查询order表
        LambdaQueryWrapper<Order> wrapper = new LambdaQueryWrapper<>();
        //查询某个用户的订单
        wrapper.eq(Order::getUserId, userId);
        //如果不为0，则查询指定状态的订单
        if (status != 0) {
            wrapper.eq(Order::getState, status);
        }
        //按下单时间倒序排列
        wrapper.orderByDesc(Order::getCreateTime);
        List<Order> orders = orderMapper.selectList(wrapper);

        //将订单对象，转换为订单视图对象
        List<OrderVo> orderVos = orders.stream().map(order -> {
            //复制订单对象的属性到OrderVo对象中
            OrderVo orderVo = BeanUtil.copyProperties(order, OrderVo.class);
            //单独设置属性
            orderVo.setStatus(order.getState());
            //订单状态文字描述
            orderVo.setOrderStatus(OrderStatus.matchCode(order.getState()).getDescribe());

            // 查询address  查询地址对象
            Address address = addressMapper.selectById(order.getAddressId());
            orderVo.setReceiver(address.getReceiver());
            orderVo.setTelephone(address.getTelephone());
            //拼接地址信息
            orderVo.setAddress(address.getProvince() + address.getCity() + address.getArea() + address.getDetailAddress());
            orderVo.setUserId(String.valueOf(userId));

            //订单明细
            LambdaQueryWrapper<Item> queryWrapper = Wrappers.lambdaQuery(Item.class).eq(Item::getOrderId, order.getId());
            //查询 item 表
            List<Item> items = itemMapper.selectList(queryWrapper);

            //订单明细转成订单项视图对象
            List<OrderItemVo> itemVos = items.stream().map(item -> {
                OrderItemVo itemVo = BeanUtil.copyProperties(item, OrderItemVo.class);
                //根据图书的ID，查询图书，获得图片地址，这个方法有缓存
                Book book = bookService.getBookById(item.getBookId());
                //只有图片名字对不上
                itemVo.setBookImg(book.getImgSrc());
                return itemVo;
            }).collect(Collectors.toList());
            //添加到订单的属性中
            orderVo.setOrderItem(itemVos);
            return orderVo;

        }).collect(Collectors.toList());

        return orderVos;
    }

    @Override
    @Transactional
    public String pay(Long orderIdStr) {
        //通过id查询订单
        Order order = getById(orderIdStr);

        //创建交易页面的支付请求对象
        AlipayTradePagePayRequest request = getAlipayTradePagePayRequest(order);

        String form;
        try {
            //调用SDK生成表单
            form = alipayClient.pageExecute(request).getBody();
            log.info("支付宝支付表单：" + form);
        } catch (AlipayApiException e) {
            e.printStackTrace();
            //让事务回滚
            throw new RuntimeException(e.getMessage());
        }

        //返回表单给控制器
        return form;
    }

    @Override
    @Transactional
    public void updateOrderStatus(String orderNum, Integer status) {
        //通过订单编号，而不是id，查询订单
        LambdaQueryWrapper<Order> queryWrapper = Wrappers.lambdaQuery(Order.class).eq(Order::getOrderNum, orderNum);
        Order order = this.getOne(queryWrapper);
        order.setState(status);
        // 更新订单
        orderMapper.updateById(order);
        //2. 修改数据库库存
        //2.1. 查询订单明细
        LambdaQueryWrapper<Item> wrapper = Wrappers.lambdaQuery(Item.class).eq(Item::getOrderId, order.getId());
        List<Item> items = itemService.list(wrapper);
        //2.2. 遍历：获取每一个商品的购买数量buy_count加、修改库存store_count减
        for (Item item : items) {
            // 修改订单项的状态
            item.setState(status);
            // 更新订单项
            itemService.updateById(item);
            // 更新书籍库存
            updateBookStorage(item);
        }
    }

    /**
     - 通过订单项更新书籍库存
     *
     - @param item
     */
    public void updateBookStorage(Item item) {
        //更新书籍
        Book book = bookService.getById(item.getBookId());
        // 修改库存 = 库存 - 购买数量
        book.setStoreCount(book.getStoreCount() - item.getBuyCount());
        // 修改购买总数 = 购买数量 + BuyCount
        book.setBuyCount(book.getBuyCount() + item.getBuyCount());
        // 更新书籍，使用乐观锁
        bookService.updateById(book);
    }

    /**
     - 创建交易页面的支付请求对象
     */
    private AlipayTradePagePayRequest getAlipayTradePagePayRequest(Order order) {
        //1.准备支付的参数，包括需要支付的订单的id，价格，物品名称
        AlipayTradePagePayModel model = new AlipayTradePagePayModel();
        model.setOutTradeNo(order.getId().toString()); // 需要支付的订单id，自定义的订单id，不能重复，唯一，已经支付的无法继续支付
        model.setTotalAmount(order.getTotalPrice().toString()); // 需要支付的钱 model.setTotalAmount("88.88");
        model.setSubject("书籍"); // 要支付的物品，比如 model.setSubject("Iphone6 16G");
        model.setProductCode("FAST_INSTANT_TRADE_PAY");  //销售产品码，电脑支付场景就使用FAST_INSTANT_TRADE_PAY

        // 2.创建支付的请求，设置上面的准备支付的参数
        AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
        request.setBizModel(model);

        // 3.设置支付宝异步回调，这个需要用内网穿透
        request.setNotifyUrl(alipayConfigOriginal.getNotifyUrl());

        // 4.设置支付宝支付成功返回的页面，这里让支付成功直接回到static下的一个静态页面中
        request.setReturnUrl(alipayConfigOriginal.getReturnUrl());
        return request;
    }

    @Override
    @Transactional
    public void cancelOrder(Long userId, String orderId) {
        Order order = orderMapper.selectById(orderId);
        order.setState(OrderStatus.ALREADY_CANCEL.getCode());
        // 更新订单
        orderMapper.updateById(order);
        //2. 修改数据库库存
        //2.1. 查询订单明细
        LambdaQueryWrapper<Item> wrapper = Wrappers.lambdaQuery(Item.class).eq(Item::getOrderId, orderId);
        List<Item> items = itemService.list(wrapper);
        //2.2. 遍历：获取每一个商品的购买数量buy_count，还原redis库存；
        HashOperations hashOperations = redisTemplate.opsForHash();
        for (Item item : items) {
            // 修改订单项的状态
            item.setState(OrderStatus.ALREADY_CANCEL.getCode());
            // 更新订单项；
            itemService.updateById(item);
            // 还原书籍库存，redis；
            hashOperations.increment(RedisConst.BOOK_STORAGE,item.getBookId().toString(),item.getBuyCount());
        }
    }

    @Override
    public void deleteOrder(Long userId, String orderId) {
        System.out.println(orderId);
        orderMapper.deleteById(orderId);
        LambdaQueryWrapper<Item> wrapper = Wrappers.lambdaQuery(Item.class).eq(Item::getOrderId, orderId);
        List<Item> items = itemService.list(wrapper);
        items.clear();
//        items.removeAll(items);
    }
}




